﻿using System.Collections.Generic;
using System.ComponentModel;
using Microsoft.Xna.Framework;
using RainEngine.SceneManagement;
using RainEngine.Controllers;
using System;
using Microsoft.Xna.Framework.Graphics;

namespace RainEngine.SceneNodes
{
    /// <summary>
    /// 这是引擎场景图的基类，引擎中的所有对象都从这个类继承。   
    /// SceneNode拥有对象的基本属性：位置，缩放，旋转。
    /// </summary>
    public abstract class SceneNode
    {
        #region 构造函数和成员变量 
      
        /// <summary>
        /// 对图形设备的引用
        /// </summary>
        protected GraphicsDevice graphicsDevice;

        /// <summary>
        /// 场景中的节点的更新顺序，更新和绘制的顺序都是基于这个值的。
        /// </summary>
        private int updateOrder;        

        /// <summary>
        /// 可以改变node的行为(大部分情况中只是位置和旋转)的控制器
        /// </summary>
        internal List<IController> controllers = new List<IController>();

        /// <summary>
        /// 是否已经初始化？在退出Initialize()方法前进行设置
        /// </summary>
        protected bool isInitialized = false;

        /// <summary>
        /// 创建一个新的SceneNode实例
        /// </summary>
        /// <param name="engine"></param>
        public SceneNode(GraphicsDevice graphicsDevice,Scene setScene)
        {            
            this.graphicsDevice = graphicsDevice;
            this.Scene = setScene;
            // 默认为3，camera = 0, sky = 1, terrain = 2!
            UpdateOrder = SceneNodeOrdering.SceneNode.GetValue();
        }

        #endregion

        #region 属性

        /// <summary>
        /// 获取或设置这个节点所属的Scene
        /// </summary>
        [Browsable(false)]
        public Scene Scene { get; set; }
                     
        /// <summary>
        /// 获取此节点是否已经初始化
        /// </summary>
        [Browsable(false)]
        public bool IsInitialized { get { return isInitialized; } }        

        /// <summary>
        /// 获取或设置这个节点的名称
        /// </summary>
        /// [Browsable(true)]
        [Category("基本属性")]
        [ParenthesizePropertyNameAttribute(true)]
        public string Name { get; set; }

        /// <summary>
        /// 用来指定节点的更新顺序。这个属性必须有一个基于<see cref="SceneNodeOrdering"/>枚举的值。
        /// </summary>    
        [Browsable(false)]
        public int UpdateOrder
        {
            get
            {
                return updateOrder;
            }
            set
            {
                if (value != updateOrder && Scene != null)
                {
                    updateOrder = value;
                    Scene.ChangeUpdateOrder(this);
                }
                else
                {
                    updateOrder = value;
                }
            }
        }        

        #endregion        

        /// <summary>
        /// 更新控制器
        /// </summary>
        /// <param name="gameTime"></param>
        public virtual void Update(GameTime gameTime)
        {
            if (controllers.Count > 0)
                for (int i = 0; i < controllers.Count; i++)
                    controllers[i].Update(gameTime);
        }

        /// <summary>
        /// 初始化
        /// </summary>
        public abstract void Initialize();

        /// <summary>
        /// 在这个SceneNode上连接一个新Controller
        /// </summary>
        /// <param name="controller">IController接口</param>
        public void AttachController(IController controller)
        {
            if (!controllers.Contains(controller))
            {
                controllers.Add(controller);
                controller.AttachNode(this);
            }
        }

        /// <summary>
        /// 从这个SceneNode移除一个Controller
        /// </summary>
        /// <param name="controller">IController接口</param>
        public void DetachController(IController controller)
        {
            if (controllers.Contains(controller))
            {
                controllers.Remove(controller);
                controller.DetachNode();
            }
        }        

        /// <summary>
        /// 当位置发生改变时调用。
        /// </summary>
        public virtual void OnPositionChange() { }

        /// <summary>
        /// 当缩放发生改变时调用。
        /// </summary>
        public virtual void OnScaleChange() { }
    }
    
}
